#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include"shep_json.h"

using namespace std;

static int main_ret = 0;  //返回值  0 -- 正常  1 -- 异常
static int test_count = 0;//总测试数
static int test_pass = 0; //通过的测试数

// template<typename T>
// inline void except_eq_base(bool equality, const T& expect, const T& actual){
//     test_count++;
//     if(equality){
//         test_pass++;
//     }
//     else{
//         cerr << __FILE__ << ":" << __LINE__ << ": expect: \" " << expect << " \" actual: \" " << actual
//              << " \"" << endl; 
//         main_ret = 1;
//     }
// }

#define EXPECT_EQ_BASE(equality, expect, actual, format)\
do{\
    test_count++;\
    if(equality)\
        test_pass++;\
    else{\
        fprintf(stderr, "%s:%d: expect: " format " actual: " format "\n", __FILE__, __LINE__, expect, actual);\
        main_ret = 1;\
    }\
}while(0)

// inline void except_eq_int(const int& except, const int& actual){
//     except_eq_base<int>((except == actual), except, actual);
// }

#define EXPECT_EQ_INT(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%d")
#define EXPECT_EQ_DOUBLE(expect, actual) EXPECT_EQ_BASE((expect) == (actual), expect, actual, "%.17g")

static void test_parse_null(){
    shep_value v;
    v.set_type(SHEP_FALSE);
    EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, "null"));
    EXPECT_EQ_INT(SHEP_NULL, v.get_type());
}

static void test_parse_true(){
    shep_value v;
    v.set_type(SHEP_FALSE);
    EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, "true"));
    EXPECT_EQ_INT(SHEP_TRUE, v.get_type()); 
}

static void test_parse_false(){
    shep_value v;
    v.set_type(SHEP_NULL);
    EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, "false"));
    EXPECT_EQ_INT(SHEP_FALSE, v.get_type()); 
}

#define TEST_NUMBER(expect, json)\
    do{\
        shep_value v;\
        EXPECT_EQ_INT(SHEP_PARSE_OK, shep_parse(v, json));\
        EXPECT_EQ_INT(SHEP_NUMBER, v.get_type());\
        EXPECT_EQ_DOUBLE(expect, v.get_number());\
    } while(0)

static void test_parse_number() {
    TEST_NUMBER(0.0, "0");
    TEST_NUMBER(0.0, "-0");
    TEST_NUMBER(0.0, "-0.0");
    TEST_NUMBER(1.0, "1");
    TEST_NUMBER(-1.0, "-1");
    TEST_NUMBER(1.5, "1.5");
    TEST_NUMBER(-1.5, "-1.5");
    TEST_NUMBER(3.1416, "3.1416");
    TEST_NUMBER(1E10, "1E10");
    TEST_NUMBER(1e10, "1e10");
    TEST_NUMBER(1E+10, "1E+10");
    TEST_NUMBER(1E-10, "1E-10");
    TEST_NUMBER(-1E10, "-1E10");
    TEST_NUMBER(-1e10, "-1e10");
    TEST_NUMBER(-1E+10, "-1E+10");
    TEST_NUMBER(-1E-10, "-1E-10");
    TEST_NUMBER(1.234E+10, "1.234E+10");
    TEST_NUMBER(1.234E-10, "1.234E-10");
    TEST_NUMBER(0.0, "1e-10000"); /* must underflow */
    TEST_NUMBER(1.0000000000000002, "1.0000000000000002"); /* the smallest number > 1 */
    TEST_NUMBER( 4.9406564584124654e-324, "4.9406564584124654e-324"); /* minimum denormal */
    TEST_NUMBER(-4.9406564584124654e-324, "-4.9406564584124654e-324");
    TEST_NUMBER( 2.2250738585072009e-308, "2.2250738585072009e-308");  /* Max subnormal double */
    TEST_NUMBER(-2.2250738585072009e-308, "-2.2250738585072009e-308");
    TEST_NUMBER( 2.2250738585072014e-308, "2.2250738585072014e-308");  /* Min normal positive double */
    TEST_NUMBER(-2.2250738585072014e-308, "-2.2250738585072014e-308");
    TEST_NUMBER( 1.7976931348623157e+308, "1.7976931348623157e+308");  /* Max double */
    TEST_NUMBER(-1.7976931348623157e+308, "-1.7976931348623157e+308");
}

#define TEST_ERROR(error, json)\
    do {\
        shep_value v;\
        v.set_type(SHEP_FALSE);\
        EXPECT_EQ_INT(error, shep_parse(v, json));\
        EXPECT_EQ_INT(SHEP_NULL, v.get_type());\
    } while(0)
    
static void test_parse_expect_value(){
    TEST_ERROR(SHEP_PARSE_EXCEPT_VALUE, "");
    TEST_ERROR(SHEP_PARSE_EXCEPT_VALUE, " ");
}

static void test_parse_invalid_value(){
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "nul");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "?");

    /* invalid number */
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "+0");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "+1");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, ".123"); /* at least one digit before '.' */
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "1.");   /* at least one digit after '.' */
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "INF");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "inf");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "NAN");
    TEST_ERROR(SHEP_PARSE_INVALID_VALUE, "nan");
}

static void test_parse_root_not_singular(){
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "null x");
    /* invalid number */
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "0123"); /* after zero should be '.' , 'E' , 'e' or nothing */
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "0x0");
    TEST_ERROR(SHEP_PARSE_ROOT_NOT_SINGULAR, "0x123");
}

static void test_parse_number_too_big(){
    TEST_ERROR(SHEP_PARSE_NUMBER_TOO_BIG, "1e309");
    TEST_ERROR(SHEP_PARSE_NUMBER_TOO_BIG, "-1e309");
}

static void test_parse() {
    test_parse_null();
    test_parse_true();
    test_parse_false();
    test_parse_number();
    test_parse_expect_value();
    test_parse_invalid_value();
    test_parse_root_not_singular();
    test_parse_number_too_big();
}

int main(){
    test_parse();
    cout << test_pass << "/" << test_count << " (" << test_pass * 100.0 / test_count
    << ") passed." << endl;
    return main_ret;
}